package com.piece.module.file.util.excel;

import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.piece.core.framework.util.object.ObjectUtil;
import org.apache.poi.ss.usermodel.Cell;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Excel表格自适应宽度
 */
public class MatchExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {

    private static final int MAX_COLUMN_LENGTH = 20;
    private final Map<Integer, Map<Integer, Integer>> cache = MapUtils.newHashMapWithExpectedSize(8);

    public MatchExcelWidthStyleStrategy() {
    }

    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        boolean needSetWidth = ObjectUtil.isNotEmpty(cellDataList);
        int allSize = writeSheetHolder.excelWriteHeadProperty().getHeadMap().size();
        Field field = head.getField();
        if (null != field) {
            ColumnWidth columnWidth = field.getAnnotation(ColumnWidth.class);
            if (null != columnWidth) {
                writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth.value() * 256);
            } else if (needSetWidth) {
                calculateColumnWidth(writeSheetHolder, cell, this.dataLength(cellDataList, cell, isHead));
            }
        } else if (needSetWidth) {
            calculateColumnWidth(writeSheetHolder, cell, this.dataLength(cellDataList, cell, isHead));
        }
    }

    private void calculateColumnWidth(WriteSheetHolder writeSheetHolder, Cell cell, int dateLength) {
        if (dateLength >= 0) {
            if (dateLength > MAX_COLUMN_LENGTH) {
                dateLength = MAX_COLUMN_LENGTH;
            } else {
                dateLength += 3;
            }

            Map<Integer, Integer> maxColumnWidthMap = this.cache.computeIfAbsent(writeSheetHolder.getSheetNo(), (key) -> new HashMap(16));

            Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
            if (null == maxColumnWidth || dateLength > maxColumnWidth) {
                maxColumnWidthMap.put(cell.getColumnIndex(), dateLength);
                writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), dateLength * 256);
            }
        }
    }

    private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            WriteCellData<?> cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (null == type) {
                return -1;
            } else {
                switch(type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    case DATE:
                        return cellData.getDateValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}
